/*
 * TowerPurpleOne.java
 *
 * Created on December 14, 2007, 10:44 AM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package hextd.tower;

import hextd.hex.Hex;
import hextd.sprite.EnemySprite;
import hextd.util.Context;
import hextd.util.Geometry;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

/**
 *
 * @author hylke
 */
public class TowerBlueThree extends TowerBase {
    
    public static int price = 5000000;
    public static int damage = 40;
    public static float range = 4f;
    
    private int         fireAt = -1;
    private float       enemyX = 0;
    private float       enemyY = 0;
    private EnemySprite enemy;
    private EnemySprite.COLOR damageColor = EnemySprite.COLOR.BLUE;
    private int         charge = 0;
    private int         chargeMax = 40;
    
    private Color       transColor;
    private Stroke[]    beam1Strokes;
    private Stroke[]    beam2Strokes;
    private Stroke      beam1Stroke;
    private Stroke      beam2Stroke;
    private Color       beam1Color;
    private Color       beam2Color;
    private Shape[]     pies;
    private Color       line2Color;
    
    /** Creates a new instance of TowerRedOne */
    public TowerBlueThree(Context context, Hex hex) {
        super(TowerFactory.type.blueThree, price, damage, range);
        this.lineColor = new Color(75, 75, 255);
        this.line2Color = new Color(25, 25, 128);
        this.transColor = new Color(this.lineColor.getRed(), this.lineColor.getGreen(), this.lineColor.getBlue(), 100);
        this.beam1Color = new Color(this.lineColor.getRed(), this.lineColor.getGreen(), this.lineColor.getBlue(), 100);
        this.beam2Color = new Color(139, 139, 255);
        this.doInit(context, hex);
    }
    
    public void doUpgrade() {
        this.level++;
        this.damageCurrent = (int)(this.damageBase * (1+this.level) * (float)Math.pow(1.05, this.level));
        this.calcDamageRange();
        this.fireTowerChangedEvent();
    }
    
    protected void calcDamageRange() {
        float lvl = (float)((1+this.level) * (float)Math.pow(1.05, this.level));
        float upg = (1f + 0.25f*this.upgradeDamage.size());
        this.damageCurrent = (int)(this.damageBase * lvl * upg );
        this.damageText = ""+this.form.format(0.1f*this.damageBase)+"*"+this.form.format(lvl)+"*"+this.form.format(upg)+"="+this.form.format(0.1f*this.damageCurrent);
        
        lvl = (float)Math.pow(1.07, this.level);
        upg = (1f + 0.25f*this.upgradeRange.size());
        this.rangeCurrent = this.rangeBase * lvl * upg;
        this.rangeText = ""+this.form.format(this.rangeBase)+"*"+this.form.format(lvl)+"*"+this.form.format(upg)+"="+this.form.format(this.rangeCurrent);
        
        this.rangePaint = this.rangeCurrent * this.paintScale;
        this.rangeCurrent2 = this.rangeCurrent*this.rangeCurrent;
        this.rangeCircle = new Ellipse2D.Float(-rangePaint, -rangePaint, rangePaint*2, rangePaint*2);
    }
    
    public void doTick(int gameTime) {
        if (this.charge == 0) {
            // Find a target
            int enemyNr = this.findEnemy(this.fireAt, true);
            this.fireAt = enemyNr;
            if (enemyNr >= 0) {
                this.charge++;
                this.enemy = this.context.enemies[enemyNr];
                this.enemyX = enemy.getX();
                this.enemyY = enemy.getY();
            }
        }
        if (this.charge > 0) {
            // Still a valid target?
            if (this.enemy.validTarget()) {
                this.charge++;
                if (this.charge >= this.chargeMax) {
                    enemy.doDamage(1f*this.damageCurrent/10, EnemySprite.DamageType.time, this.damageColor);
                    this.charge=0;
                } else {
                    this.beam1Stroke = this.beam1Strokes[this.charge-1];
                    this.beam2Stroke = this.beam2Strokes[this.charge-1];
                }
            } else {
                this.charge = 0;
                this.enemy = null;
            }
        }
    }
    
    public String getStatusString() {
        String retString = "";
        retString += "<h1>Blue Tower 1</h1>" +
                "<p>" +
                "<b>Level:</b> "+(1+this.level)+"<br>\n" +
                "<b>Rewind:</b> "+this.damageText+"<br>\n" +
                "<b>Range:</b> "+this.rangeText+"<br>" +
                "<b>Refire rate:</b> 2/s"+
                "</p>\n";
        return retString;
    }
    
    public String getInfoString() {
        String retString = "";
        retString += "<h1>Blue Tower 3</h1>" +
                "<p>" +
                "This tower generates a rift in the space-time continuum, causing it's target to be thrown back in time. " +
                "<br>Strong against blue enemies, very weak against yellow enemies." +
                "</p>" +
                "<p>" +
                "<b>Price:</b> "+this.form.format(this.price)+"<br>" +
                "<b>Rewind:</b> "+this.form.format(1f*this.damageCurrent/10f)+"<br>" +
                "<b>Range:</b> "+this.form.format(rangeCurrent)+"<br>" +
                "<b>Refire rate:</b> 2/s"+
                "</p>";
        return retString;
    }
    
    protected void generateShapes() {
        float width = this.context.hexPaintWidth;
        float scale2 = 0.5f*this.paintScale;
        int shapeCount = 2;
        int s;
        
        
        float[][] points2 = Geometry.createPolyCoords(this.paintScale);
        GeneralPath polyHex = Geometry.coordsToGeneralPath(points2, true);
        
        Area tower = new Area(polyHex);
        
        float[][] points1 = Geometry.createPolyCoords(scale2);
        polyHex = Geometry.coordsToGeneralPath(points1, true);
        Area tempArea = new Area(polyHex);
        
        tower.subtract(tempArea);
        
        GeneralPath poly = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
        poly.append(new Line2D.Float(points2[0][0], points2[0][1], points2[2][0], points2[2][1]), true);
        poly.append(new Line2D.Float(points2[2][0], points2[2][1], points2[4][0], points2[4][1]), true);
        poly.append(new Line2D.Float(points2[4][0], points2[4][1], points2[0][0], points2[0][1]), true);
        poly.append(new Line2D.Float(points2[1][0], points2[1][1], points2[3][0], points2[3][1]), false);
        poly.append(new Line2D.Float(points2[3][0], points2[3][1], points2[5][0], points2[5][1]), true);
        poly.append(new Line2D.Float(points2[5][0], points2[5][1], points2[1][0], points2[1][1]), true);
        tower.subtract(new Area(poly));

        s=0;
        this.shapes = new Shape[shapeCount];
        this.shapes[s++] = tower;
        this.shapes[s++] = new Ellipse2D.Float(-1.0f*this.context.strokeScale, -1.0f*this.context.strokeScale, 2.0f*this.context.strokeScale, 2.0f*this.context.strokeScale);
        
        
        this.strokes = new Stroke[1];
        this.strokes[0] = new BasicStroke(2.0f*this.context.strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
        
        float max = this.chargeMax;
        this.pies = new Shape[this.chargeMax+1];
        for (int i=0; i<this.pies.length; i++) {
            this.pies[i] = new Arc2D.Float(-scale2, -scale2, scale2*2, scale2*2, 0, 360f*i/(max-1), Arc2D.PIE);
        }
        
        this.beam1Strokes = new Stroke[this.chargeMax];
        this.beam2Strokes = new Stroke[this.chargeMax];
        for (int i=0; i<this.chargeMax; i++) {
            this.beam1Strokes[i] = new BasicStroke(6.0f* (float)i /max*this.context.strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
            this.beam2Strokes[i] = new BasicStroke(3.0f* (float)i /max*this.context.strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
        }
    }
    
    public void paint(Graphics2D g2, int gameTime) {
        Stroke defaultStroke = g2.getStroke();
        AffineTransform saveXform = g2.getTransform();
        
        g2.transform(atTranslate);
        
        g2.setColor(this.lineColor);
        g2.setStroke(this.strokes[0]);
        g2.fill(this.pies[this.charge]);
        
        g2.setColor(this.line2Color);
        g2.fill(this.shapes[0]);
        
        g2.setColor(this.lineColor);
        g2.draw(this.shapes[0]);
        g2.draw(this.shapes[1]);
        
        g2.setFont(this.levelFont);
        g2.drawString(""+(this.level+1), this.levelLocation[0], this.levelLocation[1]);
        
        if (this.selected) {
            g2.setColor(this.rangeColor);
            g2.draw(this.rangeCircle);
        }
        
        g2.setTransform(saveXform);
        g2.setStroke(defaultStroke);
        
    }
    
    public void paintEffects(Graphics2D g2, int gameTime) {
        Stroke defaultStroke = g2.getStroke();
        
        if (this.fireAt > -1 && this.charge > 0) {
            float ex = this.enemy.getPaintX();
            float ey = this.enemy.getPaintY();
            g2.setColor(this.beam1Color);
            g2.setStroke(this.beam1Stroke);
            g2.draw(new Line2D.Float(this.xPaint, this.yPaint, ex, ey));
            g2.setColor(this.beam2Color);
            g2.setStroke(this.beam2Stroke);
            g2.draw(new Line2D.Float(this.xPaint, this.yPaint, ex, ey));
        }
        
        g2.setStroke(defaultStroke);
    }
}
